import pytz
from django.db.models import Q
from django.shortcuts import render
from rest_framework import status

from coupon.models import UserCouponModel
from tools.myredis import r
from rest_framework.views import APIView
from rest_framework.response import Response
import json, datetime
from goods.views import getcart
from django.db import transaction
import snowflake.client
from recommend.models import GoodsModel
import time
from order.models import OrderModel0,OrderModel1,OrderModel2,OrderGoodsModel0,OrderGoodsModel1,OrderGoodsModel2
from coupon.models import UserCouponModel
from django.utils import timezone


# Create your views here.


def get_model(user_id):
    table_id = hash(user_id) % 3
    print(table_id)
    if table_id == 0:
        order_model = OrderModel0
        order_goods_model = OrderGoodsModel0
    elif table_id == 1:
        order_model = OrderModel1
        order_goods_model = OrderGoodsModel1
    else:
        order_model = OrderModel2
        order_goods_model = OrderGoodsModel2
    return order_model,order_goods_model







class GetOrders(APIView):

    def get(self, request):
        now = datetime.datetime.utcnow()
        user_id = self.request.query_params.get('user_id')
        cart_data,total = getcart(user_id)
        cart_data_list = []
        for i in cart_data:
            if i['check_status'] == "1":
                cart_data_list.append(i)
        user_data = list(UserCouponModel.objects.filter(Q(user_id=user_id) & Q(coupon__status=1) & Q(coupon__condition__lte=total)
                                                   & Q(coupon__end_time__gte=now) & Q(coupon__start_time__lte=now) & Q(status=0)).values('id','coupon__name','coupon__coupon_type','coupon__reduction'))
        return Response({'cart': cart_data_list, 'coupons': user_data, 'total': total})

    def post(self, request):
        user_id = int(request.data.get('user_id'))
        now = datetime.datetime.utcnow()
        if r.setnx_str('orderlock{}'.format(user_id), '1'):
            try:
                coupon_id = request.data.get('coupon_id')
                address = request.data.get('address')
                cart_data,total = getcart(user_id)
                cart_data_list = []
                for i in cart_data:
                    if i['check_status'] == "1":
                        cart_data_list.append(i)

                if coupon_id != 0:
                    coupon = UserCouponModel.objects.filter(Q(user_id=user_id) & Q(coupon__status=1) & Q(coupon__condition__lte=total)
                                                       & Q(coupon__end_time__gte=now) & Q(coupon__start_time__lte=now) & Q(coupon_id=coupon_id) & Q(status=0)).first()
                    if coupon is None:
                        raise Exception('优惠券不存在')

                with transaction.atomic():
                    sid = transaction.savepoint()
                    try:
                        order_id = snowflake.client.get_guid()
                        cart_id_list = [i["id"] for i in cart_data_list]
                        cart_dict = {i["id"] : i for i in cart_data_list}
                        goods_data = GoodsModel.objects.filter(id__in=cart_id_list)
                        print(goods_data)
                        for i in goods_data:
                            if i.store - i.lockstore < cart_dict[i.id]['count']:
                                transaction.savepoint_rollback(sid)
                                raise Exception('库存不足')
                            else:
                                i.lockstore += cart_dict[i.id]['count']
                                i.save()
                        order_model,order_goods_model = get_model(user_id)

                        if coupon_id != 0:
                            order = order_model.objects.create(
                                user_id=user_id,
                                total_price=total,
                                reduce_price=coupon.coupon.reduction,
                                pay_price=total-coupon.coupon.reduction,
                                usercoupon_id=coupon_id,
                                status=0,
                                order_id=order_id,
                                address=address
                            )
                            coupon.status = 1
                            coupon.save()
                        else:
                            order = order_model.objects.create(
                                user_id=user_id,
                                total_price=total,
                                reduce_price=0,
                                pay_price=total,
                                status=0,
                                order_id=order_id,
                                address=address
                            )
                        print(order)

                        for i in goods_data:
                            order_goods_model.objects.create(
                                    user_id=user_id,
                                    order_id=order_id,
                                    goods_id=i.id,
                                    count=cart_dict[i.id]['count'],
                                    price=i.price
                            )
                        with r.pipeline() as pipe:
                            pipe.multi()
                            for i in cart_id_list:
                                pipe.hdel('cart{}'.format(user_id), i)

                            pipe.execute()
                    except Exception as e:
                        transaction.savepoint_rollback(sid)
                        raise e
                    else:
                        transaction.savepoint_commit(sid)
                        print('抢购成功')
                        r.str_del('orderlock{}'.format(user_id))
                        return Response({"order_id": order_id, 'msg':'购买成功'})
            except Exception as e:
                r.str_del('orderlock{}'.format(user_id))
                raise e
        else:
            print('抢购失败')
        return Response('ok')


def get_order(user_id,type):
    order_model, order_goods_model = get_model(user_id)
    if type == 0:
        order_data = order_model.objects.filter(Q(user_id=user_id) & Q(status=0))
    elif type == 1:
        order_data = order_model.objects.filter(Q(user_id=user_id))
    else:
        return Response('参数错误')
    order_id_list = [i.order_id for i in order_data]
    coupon_id_list = [i.usercoupon_id for i in order_data]
    order_goods_data = order_goods_model.objects.filter(order_id__in=order_id_list).values('order_id', 'goods__name',
                                                                                           'count', 'price')
    order_goods_dict = {}
    for i in order_goods_data:
        if i['order_id'] not in order_goods_dict:
            order_goods_dict[i['order_id']] = []
            order_goods_dict[i['order_id']].append(
                {
                    'name': i['goods__name'],
                    'count': i['count'],
                    'price': i['price']
                }
            )
        else:
            order_goods_dict[i['order_id']].append(
                {
                    'name': i['goods__name'],
                    'count': i['count'],
                    'price': i['price']
                }
            )
    coupon_data = UserCouponModel.objects.filter(id__in=coupon_id_list).values('coupon__name', 'id')
    coupon_dict = {}
    for i in coupon_data:
        coupon_dict[i['id']] = i['coupon__name']
    order_data_read = []
    for i in order_data:
        order_data_read.append({
            'order_id': i.order_id,
            'total_price': i.total_price,
            'reduce_price': i.reduce_price,
            'pay_price': i.pay_price,
            'usercoupon_id': i.usercoupon_id,
            'pay_type': i.get_pay_type_display(),
            'status': i.get_status_display(),
            # 'create_time': i.create_time.astimezone(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S"),
            'create_time': timezone.localtime(i.create_time).strftime("%Y-%m-%d %H:%M:%S"),
            'address': i.address,
            'user_id': i.user_id,
            'order_goods': order_goods_dict[i.order_id],
        })
    for j in order_data_read:
        if j['usercoupon_id'] is not None:
            j['usercoupon_name'] = coupon_dict[j['usercoupon_id']]


    return order_data_read


class GetPayOrderAPIView(APIView):
    def get(self, request):
        user_id = int(self.request.query_params.get('user_id'))
        order_data_read = get_order(user_id, 0)

        return Response(order_data_read)

from tools.pay import get_alipay
class Pay(APIView):
    def post(self, request):
        user_id = int(request.data.get('user_id'))
        order_id = str(request.data.get('order_id'))

        order_model,order_goods_model = get_model(user_id)

        order_data = order_model.objects.filter(Q(user_id=user_id) & Q(order_id=order_id)).first()

        if not order_data:
            return Response({'msg':'订单不存在'}, status=status.HTTP_400_BAD_REQUEST)
        pay_money = order_data.pay_price

        table_id = hash(user_id) % 3


        trade_id = str(table_id) + order_id

        r.set_str('order{}'.format(trade_id),'1')
        # from datetime import datetime, timedelta
        # eta = datetime.utcnow() + timedelta(minutes=5)
        # print(datetime.now())
        # result = check_order.apply_async(args=[trade_id], eta=eta)


        # 查询订单
        pay = get_alipay()
        # 根据订单号查询订单表
        query_params = pay.direct_pay(
            subject="家政服务",  # 商品简单描述
            out_trade_no=trade_id,  # 用户购买的商品订单号（每次不一样） 20180301073422891
            total_amount=float(pay_money),  # 交易金额(单位: 元 保留俩位小数)
        )
        payUrl = "https://openapi-sandbox.dl.alipaydev.com/gateway.do?{0}".format(query_params)

        return Response({"code": 200,'url':payUrl})


class Alipaycallback(APIView):
    def get(self,request):
        data = request.GET
        mes = {k:v for k,v in data.items()}
        #验证签名
        pay = get_alipay()
        sign = mes.pop('sign')
        flag = pay.verify(mes,sign)
        if flag:
            orderno = data['out_trade_no']
            trade_no = data['trade_no']
            table_id = int(orderno[0])
            order_id = orderno[1:]

            order_model = [OrderModel0, OrderModel1,OrderModel2][table_id]
            order_goods_model = [OrderGoodsModel0, OrderGoodsModel1][table_id]
            order_data = order_model.objects.filter(order_id=order_id).first()
            order_goods_data = order_goods_model.objects.filter(order_id=order_id).all()
            # print("----------------")
            # print(order_goods_data)
            with transaction.atomic():
                sid = transaction.savepoint()
                try:
                    order_data.status = 1
                    order_data.trade_id = trade_no
                    order_data.save()
                    order_goods_id_list = [i.goods_id for i in order_goods_data]
                    goods_data = GoodsModel.objects.filter(id__in=order_goods_id_list).all()
                    pid_list = {i.pid_id for i in goods_data}
                    order_goods_dict = {i.goods_id:i for i in order_goods_data}
                    print(order_goods_dict)
                    for i in goods_data:
                        i.store -= order_goods_dict[i.id].count
                        i.lockstore -= order_goods_dict[i.id].count
                        i.save()

                    with r.pipeline() as pipe:
                        pipe.multi()
                        for i in list(pid_list):
                            pipe.delete("goodscategory{}".format(i))
                        for i in order_goods_id_list:
                            pipe.delete("goodsdetail{}".format(i))

                        pipe.execute()
                except:
                    transaction.savepoint_rollback(sid)
                    return Response({'msg':'error','code':100010})
                else:
                    r.str_del('order{}'.format(orderno))
                    transaction.savepoint_commit(sid)
            return Response({'msg':'ok','code':200})
        else:
            return Response({'msg':'error','code':100010})


class OrderListAPIView(APIView):
    def get(self, request):
        user_id = int(self.request.query_params.get('user_id'))
        order_data_read = get_order(user_id, 1)

        return Response(order_data_read)

def CheckOrder(id):
    if r.get_str('order{}'.format(id)):
        table_id = int(id[0])
        order_id = id[1:]
        order_model = [OrderModel0, OrderModel1,OrderModel2][table_id]
        order_goods_model = [OrderGoodsModel0, OrderGoodsModel1][table_id]
        order_data = order_model.objects.filter(order_id=order_id).first()
        order_goods_data = order_goods_model.objects.filter(order_id=order_id).all()
        with transaction.atomic():
            sid = transaction.savepoint()
            try:
                order_data.status = 5
                order_data.save()
                order_goods_id_list = [i.goods_id for i in order_goods_data]
                goods_data = GoodsModel.objects.filter(id__in=order_goods_id_list).all()
                pid_list = {i.pid_id for i in goods_data}
                order_goods_dict = {i.goods_id: i for i in order_goods_data}
                print(order_goods_dict)
                for i in goods_data:
                    i.lockstore -= order_goods_dict[i.id].count
                    i.save()


                if order_data.usercoupon:
                    order_data.usercoupon.status = 0
                    order_data.usercoupon.save()



                with r.pipeline() as pipe:
                    pipe.multi()
                    for i in list(pid_list):
                        pipe.delete("goodscategory{}".format(i))
                    for i in order_goods_id_list:
                        pipe.delete("goodsdetail{}".format(i))

                    pipe.execute()
            except:
                transaction.savepoint_rollback(sid)
                return Response({'msg': 'error', 'code': 100010})
            else:
                r.str_del('order{}'.format(id))
                transaction.savepoint_commit(sid)







from base.tasks import check_order
class OrdersView(APIView):
    def get(self,request):
        orderno='10010'
        from datetime import datetime, timedelta
        eta = datetime.utcnow() + timedelta(seconds=5)
        print(datetime.now())
        result =check_order.apply_async(args=[orderno], eta=eta)
        print(f"Delayed Task ID: {result.task_id}")

        return Response('ok')
